
package com.hlkj.pay.app.merchant.ext.impl.huifu.handler.params;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.date.DatePattern;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.huifu.dto.V2TradeHostingPaymentPreorderRequest;
import com.hlkj.pay.app.merchant.ext.impl.huifu.dto.order.HuiFuHostingPayOrderResultDto;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.order.RefundOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.vo.order.req.PayOrderCommonParamReq;
import com.hlkj.pay.vo.order.req.PayOrderParamReq;
import com.huifu.bspay.sdk.opps.core.request.*;
import com.huifu.bspay.sdk.opps.core.utils.SequenceTools;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * @author HlpayTeam
 * @date 2024/09/26 10:25
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Component
public class HuiFuPayOrderRequestParamsHandler {

    /**
     * 汇付正扫提交订单  非原生
     * 
     * @return
     */
    public static V2TradeHostingPaymentPreorderRequest v2TradePaymentHostingRequest(ChannelPayOrderContext channelPayOrderContext) {
        PayOrderDO orderDO = channelPayOrderContext.getPayOrderDO();
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        // 2.组装请求参数
        V2TradeHostingPaymentPreorderRequest request = new V2TradeHostingPaymentPreorderRequest();
        // 请求日期
        request.setReqDate(DateUtils.getDateString(DatePattern.PURE_DATE_PATTERN));
        // 请求流水号
        request.setReqSeqId(orderDO.getPayOrderNo());
        request.setTimeExpire(DateUtils.dateToString(orderDO.getExpiredTime(), "yyyyMMddHHmmss"));
        switch (PayEnums.PAY_TYPE.fromByCode(payWayDO.getType())) {
            case ALIPAY:
                // 预下单类型
                request.setPreOrderType("2");
                // app扩展参数集合
                if (StringUtils.hasText(orderDO.getExtra())) {
                    PayOrderParamReq.Extra extra = JsonUtils.parseObject(orderDO.getExtra(), PayOrderParamReq.Extra.class);
                    // 支付授权码
                    request.setAppData(getAppData(extra));
                }
                break;
            case WECHAT:
                // 预下单类型
                request.setPreOrderType("3");
                request.setMiniAppData(getMiniAppData());
                break;
            default:
                channelPayOrderContext.setRemark("汇付app支付 目前只支付微信支付宝");
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
        // 交易金额
        request.setTransAmt(MerchantUtils.bigDecimalToString2(orderDO.getAmount()));
        Map<String, Object> extendInfoMap = getExtendInfos(channelPayOrderContext);
        request.setExtendInfo(extendInfoMap);
        // 商品描述
        request.setGoodsDesc(orderDO.getSubject());
        return request;
    }

    private static String getMiniAppData() {
        JSONObject dto = new JSONObject();
        // 是否生成scheme_code Y；适用于APP、短信链接、邮件、外部网页、微信内等拉起汇付小程序的业务场景时需填Y；
        // N；通过汇付微信插件支付填N；
        dto.put("need_scheme", "Y");
        // 私有信息
        // dto.put("private_info", "192.168.1.1");
        // 应用ID
        // dto.put("seq_id", "33.3");
        return dto.toJSONString();
    }

    private static String getAppData(PayOrderParamReq.Extra extra) {
        JSONObject dto = new JSONObject();
        // 小程序返回码
        if (extra != null) {
            dto.put("app_schema", "");
        }
        // 私有信息
        // dto.put("private_info", "192.168.1.1");
        return dto.toJSONString();
    }

    /**
     * 正扫提交订单参数处理
     *
     * @param response
     * @param channelMerchantAccessContext
     */
    public static void processSubmitOrderResultData(Map<String, Object> response, ChannelPayOrderContext channelMerchantAccessContext) {
        if (CollectionUtils.isEmpty(response)) {
            channelMerchantAccessContext.setRemark("斗拱提交APP支付订单返回信息为空");
            channelMerchantAccessContext.setProcessStatus(Boolean.FALSE);
            return;
        }

        HuiFuHostingPayOrderResultDto scanPayOrderResultDto = JSONObject.parseObject(response.toString(), HuiFuHostingPayOrderResultDto.class);
        if ("00000000".equals(scanPayOrderResultDto.getResp_code()) || "00000100".equals(scanPayOrderResultDto.getResp_code())) {
            JSONObject miniObje = JSONObject.parseObject(scanPayOrderResultDto.getMiniapp_data());
            channelMerchantAccessContext.setPayOrderStatus(PayOrderEnums.PAY_ORDER_STATUS.PAYING);

            channelMerchantAccessContext.setPayDataType("data");
            Map<String,String> payInfo = new HashMap<>();
            payInfo.put("userName", miniObje.getString("gh_id"));
            payInfo.put("path", miniObje.getString("path"));
            payInfo.put("schemeCode", miniObje.getString("scheme_code"));
            channelMerchantAccessContext.setPayInfo(JSONUtil.toJsonStr(payInfo));
        }
        else {
            String respDesc = scanPayOrderResultDto.getResp_desc();
            channelMerchantAccessContext.setProcessStatus(Boolean.FALSE);
            if (StringUtils.hasText(respDesc)) {
                channelMerchantAccessContext.setRemark(respDesc);
            }
            else {
                channelMerchantAccessContext.setRemark("斗拱提交APP支付订单返回错误信息为空,错误码为:" + scanPayOrderResultDto.getResp_code());
            }

        }
    }

    /**
     * 汇付正扫提交订单
     *
     * @return
     */
    public static V2TradePaymentJspayRequest v2TradePaymentJspayRequest(ChannelPayOrderContext channelPayOrderContext) {
        PayOrderDO orderDO = channelPayOrderContext.getPayOrderDO();
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        // 2.组装请求参数
        V2TradePaymentJspayRequest request = new V2TradePaymentJspayRequest();
        // 请求日期
        request.setReqDate(DateUtils.getDateString(DatePattern.PURE_DATE_PATTERN));
        // 请求流水号
        request.setReqSeqId(orderDO.getPayOrderNo());
        // 商户号
        // request.setHuifuId("6666000108854952");
        // 交易类型
        request.setTradeType(buildTradeType(payWayDO));
        // 交易金额
        request.setTransAmt(MerchantUtils.bigDecimalToString2(orderDO.getAmount()));
        // 商品描述
        request.setGoodsDesc(orderDO.getSubject());

        // 设置非必填字段
        Map<String, Object> extendInfoMap = getExtendInfos(channelPayOrderContext);
        request.setExtendInfo(extendInfoMap);
        return request;
    }

    /**
     * 汇付反扫提交订单
     *
     * @param channelPayOrderContext
     * @return
     */
    public static V2TradePaymentMicropayRequest v2TradePaymentMicropayRequest(ChannelPayOrderContext channelPayOrderContext) {
        PayOrderDO orderDO = channelPayOrderContext.getPayOrderDO();
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        // 2.组装请求参数
        V2TradePaymentMicropayRequest request = new V2TradePaymentMicropayRequest();
        // 请求日期
        request.setReqDate(DateUtils.getDateString(DatePattern.PURE_DATE_PATTERN));
        // 请求流水号
        request.setReqSeqId(orderDO.getPayOrderNo());
        // 商户号
        // request.setHuifuId("6666000018328947");
        // 交易金额
        request.setTransAmt(MerchantUtils.bigDecimalToString2(orderDO.getAmount()));
        // 商品描述
        request.setGoodsDesc(orderDO.getSubject());
        if (StringUtils.hasText(orderDO.getExtra())) {
            PayOrderParamReq.Extra extra = JsonUtils.parseObject(orderDO.getExtra(), PayOrderParamReq.Extra.class);
            // 支付授权码
            request.setAuthCode(extra.getAuthCode());
        }
        // 设置非必填字段
        Map<String, Object> extendInfoMap = getMicroPayExtendInfos(channelPayOrderContext);
        request.setExtendInfo(extendInfoMap);
        return request;
    }

    /**
     * 汇付正扫关闭订单
     *
     * @return
     */
    public static V2TradePaymentScanpayCloseRequest v2TradePaymentScanpayCloseRequest(ChannelPayOrderQueryContext channelPayOrderContext) {
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        // 2.组装请求参数
        V2TradePaymentScanpayCloseRequest request = new V2TradePaymentScanpayCloseRequest();
        // 请求日期
        request.setReqDate(DateUtils.getDateString(DatePattern.PURE_DATE_PATTERN));
        // 请求流水号
        request.setReqSeqId(SequenceTools.getReqSeqId32());
        // 商户号
        // request.setHuifuId("6666000018328947");
        // 原交易请求日期
        request.setOrgReqDate(DateUtils.dateToString(payOrderDO.getCreateTime(), "yyyyMMdd"));

        // 设置非必填字段
        Map<String, Object> extendInfoMap = getExtendInfos(payOrderDO);
        request.setExtendInfo(extendInfoMap);
        return request;
    }

    /**
     * 汇付正扫关闭订单
     *
     * @return
     */
    public static V2TradePaymentScanpayClosequeryRequest v2TradePaymentScanpayClosequeryRequest(ChannelPayOrderQueryContext channelPayOrderContext) {
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        // 2.组装请求参数
        V2TradePaymentScanpayClosequeryRequest request = new V2TradePaymentScanpayClosequeryRequest();
        // 请求日期
        request.setReqDate(DateUtils.getDateString(DatePattern.PURE_DATE_PATTERN));
        // 请求流水号
        request.setReqSeqId(SequenceTools.getReqSeqId32());
        // 商户号
        // request.setHuifuId("6666000018328947");
        // 原交易请求日期
        request.setOrgReqDate(DateUtils.dateToString(payOrderDO.getCreateTime(), "yyyyMMdd"));

        // 设置非必填字段
        Map<String, Object> extendInfoMap = getExtendInfos(payOrderDO);
        request.setExtendInfo(extendInfoMap);
        return request;
    }

    /**
     * 汇付正扫订单退款
     *
     * @return
     */
    public static V2TradePaymentScanpayRefundRequest v2TradePaymentScanpayRefundRequest(ChannelRefundPayOrderContext channelPayOrderContext) {
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        RefundOrderDO refundOrderDO = channelPayOrderContext.getRefundOrderDO();
        // 2.组装请求参数
        V2TradePaymentScanpayRefundRequest request = new V2TradePaymentScanpayRefundRequest();
        // 请求日期
        request.setReqDate(DateUtils.getDateString(DatePattern.PURE_DATE_PATTERN));
        // 请求流水号
        request.setReqSeqId(refundOrderDO.getRefundOrderNo());
        // 商户号
        // request.setHuifuId("6666000018328947");
        // 原交易请求日期
        request.setOrgReqDate(DateUtils.dateToString(payOrderDO.getCreateTime(), "yyyyMMdd"));
        request.setOrdAmt(MerchantUtils.bigDecimalToString2(refundOrderDO.getRefundAmount()));
        // 设置非必填字段
        Map<String, Object> extendInfoMap = getExtendInfos(payOrderDO);
        request.setExtendInfo(extendInfoMap);
        return request;
    }

    /**
     * 非必填字段
     *
     * @return
     */
    private static Map<String, Object> getExtendInfos(PayOrderDO payOrderDO) {
        // 设置非必填字段
        Map<String, Object> extendInfoMap = new HashMap<>();
        // 原交易返回的全局流水号
        // extendInfoMap.put("org_hf_seq_id", "");
        // 原交易请求流水号
        extendInfoMap.put("org_req_seq_id", payOrderDO.getPayOrderNo());
        return extendInfoMap;
    }

    /**
     * 非必填字段
     *
     * @return
     */
    private static Map<String, Object> getExtendInfos(ChannelPayOrderContext channelPayOrderContext) {
        PayOrderDO orderDO = channelPayOrderContext.getPayOrderDO();
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        // 设置非必填字段
        Map<String, Object> extendInfoMap = new HashMap<>();
        // 交易有效期
        extendInfoMap.put("time_expire", DateUtils.dateToString(orderDO.getExpiredTime(), "yyyyMMddHHmmss"));
        // 禁用信用卡标记
        // extendInfoMap.put("limit_pay_type", "NO_CREDIT");
        // 是否延迟交易
        // extendInfoMap.put("delay_acct_flag", "N");
        // 渠道号
        // extendInfoMap.put("channel_no", "");
        // 手续费扣款标志
        // extendInfoMap.put("fee_flag", "");
        // 营销补贴信息
        // extendInfoMap.put("combinedpay_data", getCombinedpayData());
        PayEnums.SCENE_TYPE sceneType = PayEnums.SCENE_TYPE.from(payWayDO.getSceneType());
        // switch (sceneType) {
        // case OFFLINE:
        // // 场景类型
        // extendInfoMap.put("pay_scene", "02");
        // break;
        // case ONLINE:
        // // 场景类型
        // extendInfoMap.put("pay_scene", "01");
        // break;
        // }

        // 安全信息
        extendInfoMap.put("risk_check_data", getRiskCheckData(orderDO));
        // 设备信息
        // extendInfoMap.put("terminal_device_data", getTerminalDeviceData());
        // 分账对象
        // extendInfoMap.put("acct_split_bunch", getAcctSplitBunch());
        // 传入分帐遇到优惠的处理规则
        // extendInfoMap.put("term_div_coupon_type", "0");

        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());

        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.fromByType(payWayDO.getSubType());

        switch (scenePayType) {
            case JSAPI:
            case QR:
            case MINI_APP:
                switch (payType) {
                    case WECHAT:
                        // 聚合正扫微信拓展参数集合
                        extendInfoMap.put("wx_data", getWxData(channelPayOrderContext));
                        break;
                    case ALIPAY:
                        // 支付宝扩展参数集合
                        extendInfoMap.put("alipay_data", getAlipayData(channelPayOrderContext.getExtra()));
                        break;
                }
                break;
            default:
        }
        // 银联参数集合
        // extendInfoMap.put("unionpay_data", getUnionpayData());
        // 数字人民币参数集合
        // extendInfoMap.put("dc_data", getDcData());
        // 商户贴息标记
        // extendInfoMap.put("fq_mer_discount_flag", "N");
        // 异步通知地址
        extendInfoMap.put("notify_url", channelPayOrderContext.getNotifyUrl());
        // 备注
        extendInfoMap.put("remark", orderDO.getDescription());
        // 账户号
        // extendInfoMap.put("acct_id", "");
        return extendInfoMap;
    }

    /**
     * 非必填字段
     *
     * @return
     */
    private static Map<String, Object> getMicroPayExtendInfos(ChannelPayOrderContext channelPayOrderContext) {
        PayOrderDO orderDO = channelPayOrderContext.getPayOrderDO();
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        // 设置非必填字段
        Map<String, Object> extendInfoMap = new HashMap<>();
        // 交易有效期
        extendInfoMap.put("time_expire", DateUtils.dateToString(orderDO.getExpiredTime(), "yyyyMMddHHmmss"));
        // 禁用信用卡标记
        // extendInfoMap.put("limit_pay_type", "NO_CREDIT");
        // 是否延迟交易
        // extendInfoMap.put("delay_acct_flag", "N");
        // 渠道号
        // extendInfoMap.put("channel_no", "");
        // 手续费扣款标志
        // extendInfoMap.put("fee_flag", "");
        // 营销补贴信息
        // extendInfoMap.put("combinedpay_data", getCombinedpayData());
        PayEnums.SCENE_TYPE sceneType = PayEnums.SCENE_TYPE.from(payWayDO.getSceneType());
        switch (sceneType) {
            case OFFLINE:
                // 场景类型
                extendInfoMap.put("pay_scene", "02");
                break;
            case ONLINE:
                // 场景类型
                extendInfoMap.put("pay_scene", "01");
                break;
        }
        // 安全信息
        extendInfoMap.put("risk_check_data", getRiskCheckData(orderDO));
        // 设备信息
        // extendInfoMap.put("terminal_device_data", getTerminalDeviceData());
        // 分账对象
        // extendInfoMap.put("acct_split_bunch", getAcctSplitBunch());
        // 传入分帐遇到优惠的处理规则
        // extendInfoMap.put("term_div_coupon_type", "0");
        // 银联参数集合
        // extendInfoMap.put("unionpay_data", getUnionpayData());
        // 数字人民币参数集合
        // extendInfoMap.put("dc_data", getDcData());
        // 商户贴息标记
        // extendInfoMap.put("fq_mer_discount_flag", "N");
        // 异步通知地址
        extendInfoMap.put("notify_url", channelPayOrderContext.getNotifyUrl());
        // 备注
        extendInfoMap.put("remark", orderDO.getDescription());
        // 账户号
        // extendInfoMap.put("acct_id", "");
        return extendInfoMap;
    }

    private static String getRiskCheckData(PayOrderDO orderDO) {
        JSONObject dto = new JSONObject();
        // ip地址
        dto.put("ip_addr", orderDO.getClientIp());
        // 基站地址
        // dto.put("base_station", "192.168.1.1");
        // 纬度
        // dto.put("latitude", "33.3");
        // 经度
        // dto.put("longitude", "33.3");
        return dto.toJSONString();
    }

    private static String getWxData(ChannelPayOrderContext channelPayOrderContext) {
        PayOrderCommonParamReq.Extra extra = channelPayOrderContext.getExtra();

        JSONObject dto = new JSONObject();
        // 子商户公众账号id
        // dto.put("sub_appid", "");
        // 用户标识
        // dto.put("openid", "");
        // 子商户用户标识
        if (StringUtils.hasText(extra.getUserId())) {
            dto.put("sub_openid", extra.getUserId());
        }
        // 附加数据
        // dto.put("attach", "");
        // 商品描述
        // dto.put("body", "");
        // 商品详情
        // dto.put("detail", getDetail());
        // 设备号
        // dto.put("device_info", "");
        // 订单优惠标记
        // dto.put("goods_tag", "");
        // 实名支付
        // dto.put("identity", "");
        // 开发票入口开放标识
        // dto.put("receipt", "");
        // 场景信息
        // dto.put("scene_info", getSceneInfo());
        // 终端ip
        // dto.put("spbill_create_ip", "");

        return dto.toJSONString();
    }

    private static String getAlipayData(PayOrderCommonParamReq.Extra extra) {
        JSONObject dto = new JSONObject();
        // 买家的支付宝唯一用户号
        dto.put("buyer_id", extra.getUserId());
        // 支付宝的店铺编号
        // dto.put("alipay_store_id", "");
        // // 买家支付宝账号
        // dto.put("buyer_logon_id", "string");
        // // 业务扩展参数
        // dto.put("extend_params", getExtendParams());
        // // 订单包含的商品列表信息
        // dto.put("goods_detail", getGoodsDetail());
        // // 商户原始订单号
        // dto.put("merchant_order_no", "string");
        // // 商户操作员编号
        // dto.put("operator_id", "123213213");
        // // 销售产品码
        // dto.put("product_code", "string");
        // // 卖家支付宝用户号
        // dto.put("seller_id", "string");
        // // 商户门店编号
        // dto.put("store_id", "");
        return dto.toJSONString();
    }

    /**
     * 交易类型 转换
     *
     * @param
     */
    public static String buildTradeType(PayWayDO payWayDO) {
        switch (PayEnums.PAY_TYPE.fromByCode(payWayDO.getType())) {
            case WECHAT:
                switch (PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType())) {
                    case APP:
                        return "T_APP";
                    case JSAPI:
                    case QR:
                        return "T_JSAPI";
                    case H5:
                    case MINI_APP:
                        return "T_MINIAPP";
                }
                break;
            case ALIPAY:
                switch (PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType())) {
                    case JSAPI:
                        return "A_JSAPI";
                    case QR:
                        return "A_NATIVE";
                }
                break;
            case UNION_APY:
                switch (PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType())) {
                    case JSAPI:
                        return "U_JSAPI";
                    case QR:
                        return "U_NATIVE";
                }
                break;
            case DIGITAL:
                switch (PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType())) {
                    case QR:
                        return "D_NATIVE";
                }
                break;
            default:
                return null;
        }
        return null;
    }

}
